﻿
module TestSimpleGradient = 
    
    let mutable lambda = 0.1

    let sigmoid (x:float array) (y:int) (g:float array) = 
        let mutable dot = 0.0
        for i=0 to x.Length-1 do
            dot <- dot + x.[i] * g.[i+1]
        let z = (float y) * dot
        if z > 30.0 then
            1.0
        elif z < -30.0 then
            0.0
        else
            1.0 / (1.0 + exp (- z))

    let sigmoid2 (x:float array) (y:int) (g:float array) = 
        let mutable dot = 0.0
        for i=0 to x.Length-1 do
            dot <- dot + x.[i] * g.[i]
        1.0 / (1.0 + exp (- (float y) * dot))

        
    let logregValue(ds:dataset) (values:float array) = 
        let dim = ds.features.[0].Length


        let mutable L = 0.0
        for i=1 to dim do
            L <- L + values.[i]*values.[i]
        L <- - (L * lambda / 2.0)

        for i=0 to ds.features.Length-1 do
            L <- L + log ( sigmoid ds.features.[i] ds.labels.[i] values)

        printfn "L = %.10f" L
        L
            


    let logregGradient(ds:dataset) (values:float array) = 
        let dim = ds.features.[0].Length
        let gradient = Array.create (values.Length) 0.0
        
        for j=1 to dim do 
            gradient.[j] <- -lambda * values.[j]
            
        for i=0 to ds.features.Length-1 do
            let coef = (1.0 - sigmoid ds.features.[i] ds.labels.[i] values) * (float ds.labels.[i])
            for j=1 to dim do 
                gradient.[j] <- gradient.[j] + coef * ds.features.[i].[j-1]

        
        gradient



    
    let w = Array.create 6 0.0

    let step = 0.001
    for i=1 to 1000 do 
        let v = logregValue iris w
        printfn "iter = %A value = %A" i v
        let g = logregGradient iris w
        for j=1 to 5 do 
            w.[j] <- w.[j] + step * g.[j]

